Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR implements a booking system that allows passengers to create bookings for available routes. The implementation includes type definitions, validation schemas, database models, API routes, and controller logic for handling booking creation.
- Introduces booking creation functionality with validation and business logic
- Adds TypeScript types and Mongoose models for bookings
- Integrates booking routes into the main router
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| back-end/src/types/booking.types.ts | Defines TypeScript interface for booking entities with passenger, driver, route references and status |
| back-end/src/schemas/bookingSchema.ts | Defines Zod validation schemas for booking operations and queries |
| back-end/src/routes/index.ts | Registers booking routes in the main application router |
| back-end/src/routes/booking.routes.ts | Defines the booking API endpoint for creating bookings |
| back-end/src/models/route.model.ts | Exports IRouteDocument interface and updates model type for better type safety |
| back-end/src/models/booking.model.ts | Implements Mongoose schema and model for booking documents |
| back-end/src/controllers/booking.controller.ts | Implements booking creation logic with validation and business rules |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 41 out of 45 changed files in this pull request and generated 8 comments.
Files not reviewed (1)
- back-end/package-lock.json: Language not supported
Comments suppressed due to low confidence (5)
back-end/src/controllers/ride.controller.ts:1
- The
Bookingimport is not used anywhere in this file and should be removed.
back-end/src/models/ride.model.ts:119 - The commented-out lines reference "routeSchema" but should be removed entirely or updated to reference "rideSchema" if they're intended to be uncommented in the future.
back-end/src/controllers/ride.controller.ts:1 - Unused import Booking.
back-end/src/controllers/ride.controller.ts:12 - Unused import Types.
back-end/src/routes/user.routes.ts:6 - Unused import RideController.
import { RideController } from "../controllers/ride.controller";
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (ref.current) observer.observe(ref.current); | ||
|
|
||
| return () => { | ||
| if (element) observer.unobserve(element); | ||
| if (ref.current) observer.unobserve(ref.current); | ||
| }; |
There was a problem hiding this comment.
The cleanup function in the useEffect may reference a stale ref.current value. When the component unmounts, ref.current might already be null, causing the observer to not properly unobserve the element. Store the current element in a variable within the effect to ensure proper cleanup.
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
const target = entries[0];
if (target.isIntersecting) {
callback?.();
}
});
const element = ref.current;
if (element) observer.observe(element);
return () => {
if (element) observer.unobserve(element);
};
}, [callback]);| if (ref.current) observer.unobserve(ref.current); | ||
| }; | ||
| }, []); | ||
| }, [callback]); |
There was a problem hiding this comment.
The callback dependency in the useEffect will cause the IntersectionObserver to be recreated every time the callback changes, which could be on every render if the callback is not memoized. This can lead to performance issues and unexpected behavior. Consider using a ref to store the callback or removing it from the dependency array if the callback doesn't need to trigger observer recreation.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 42 out of 46 changed files in this pull request and generated 6 comments.
Files not reviewed (1)
- back-end/package-lock.json: Language not supported
Comments suppressed due to low confidence (3)
front-end/src/app/(home)/ride/[...slug]/page.tsx:90
- The string concatenation
rideData.driverProfile.rating.count + "rides"produces output like "5rides" without a space. This should be${rideData.driverProfile.rating.count} ridesor include a space in the string to produce readable output like "5 rides".
back-end/src/controllers/ride.controller.ts:1 - Unused import Booking.
back-end/src/controllers/ride.controller.ts:12 - Unused import Types.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * @route GET /api/ride/all | ||
| * @desc Get all rides | ||
| * @access Public | ||
| */ | ||
| router.get( | ||
| "/all", |
There was a problem hiding this comment.
The API endpoint ride/all is inconsistent with the RESTful design pattern used elsewhere. The old endpoint was /routes (GET all routes), and the new endpoint should simply be /ride for consistency, not /ride/all.
This creates confusion since POST /ride creates a ride, but GET requires /ride/all to list rides. The /all suffix is redundant - a GET request to /ride without an ID parameter should naturally return all rides.
| * @route GET /api/ride/all | |
| * @desc Get all rides | |
| * @access Public | |
| */ | |
| router.get( | |
| "/all", | |
| * @route GET /api/ride | |
| * @desc Get all rides | |
| * @access Public | |
| */ | |
| router.get( | |
| "/", |
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 50 out of 54 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- back-end/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 50 out of 54 changed files in this pull request and generated 5 comments.
Files not reviewed (1)
- back-end/package-lock.json: Language not supported
Comments suppressed due to low confidence (2)
front-end/src/app/(home)/ride/[...slug]/page.tsx:90
- There's a spacing issue in the string concatenation. The current code results in "(5rides )" with "rides" directly attached to the count. Add a space before "rides":
({rideData.driverProfile.rating.count} rides)back-end/src/controllers/ride.controller.ts:7
- Use relative import
../schemas/rideSchemainstead of aliased import@/schemas/rideSchemafor consistency.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| try { | ||
| const response = await api | ||
| .url(`ride/all?${queryString}`) |
There was a problem hiding this comment.
[nitpick] The API endpoint in the front-end uses /ride/all to fetch rides, but there's an inconsistency: the comment in the backend route says "Get all rides" but the actual endpoint likely expects query parameters for filtering (as seen in getRideQuerySchema). Consider renaming to /ride/search or /rides for better semantic clarity.
| .url(`ride/all?${queryString}`) | |
| .url(`rides?${queryString}`) |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 60 out of 64 changed files in this pull request and generated 6 comments.
Files not reviewed (1)
- back-end/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
front-end/src/app/(home)/ride/[...slug]/page.tsx:222
- The
isBookingAvailableprop is always set totrue, but it should be calculated based onrideData.remainingSeats > 0. This means the booking button will always appear enabled even when there are no seats available.
Change to:
<BookingButton rideId={rideData._id} isBookingAvailable={rideData.remainingSeats > 0} />💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| state.queuedRequests.forEach(async ({ req }) => { | ||
| try { | ||
| const result = await req | ||
| return await req | ||
| .auth(`Bearer ${newToken}`) | ||
| .customError( | ||
| async (error: WretchError, response: WretchResponse) => { | ||
| return { ...error, json: await response.json() }; | ||
| } | ||
| ) | ||
| .fetch() | ||
| .json((json: { data: any }) => json?.data); | ||
| return result; | ||
| } catch (err) { | ||
| throw err; | ||
| } | ||
| }); |
There was a problem hiding this comment.
The queued requests replay logic doesn't handle the response properly. The return statement inside the forEach callback doesn't return from the main function, and there's no mechanism to resolve/reject promises for the queued requests. This means queued requests will hang indefinitely.
Consider implementing a proper queue with promise resolution:
state.queuedRequests.forEach(async ({ req, resolve, reject }) => {
try {
const result = await req
.auth(`Bearer ${newToken}`)
.customError(
async (error: WretchError, response: WretchResponse) => {
return { ...error, json: await response.json() };
}
)
.fetch()
.json((json: { data: any }) => json?.data);
resolve?.(result);
} catch (err) {
reject?.(err);
}
});| const state = { | ||
| isRefreshingToken: false, | ||
| queuedRequests: new Map<string, { req: any }>(), | ||
| resolveRefreshPromise: null as ((token: string) => void) | null, | ||
| }; |
There was a problem hiding this comment.
The resolveRefreshPromise field was removed from the state object, but the queue management system is incomplete. The queued requests are stored but never properly resolved or rejected, which will cause those requests to hang indefinitely.
| useEffect(() => { | ||
| const observer = new IntersectionObserver((entries) => { | ||
| const target = entries[0]; | ||
| if (target.isIntersecting) { | ||
| callbackRef.current?.(); | ||
| callback?.(); | ||
| } | ||
| }); | ||
|
|
||
| const element = ref.current; | ||
| if (element) observer.observe(element); | ||
| if (ref.current) observer.observe(ref.current); | ||
|
|
||
| return () => { | ||
| if (element) observer.unobserve(element); | ||
| if (ref.current) observer.unobserve(ref.current); | ||
| }; | ||
| }, []); | ||
| }, [callback]); |
There was a problem hiding this comment.
The callback dependency in the useEffect can cause the observer to be recreated on every render if the callback is not memoized by the parent component. This can lead to performance issues and unexpected behavior.
Consider using a ref to store the callback:
const callbackRef = useRef(callback);
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
const target = entries[0];
if (target.isIntersecting) {
callbackRef.current?.();
}
});
const element = ref.current;
if (element) observer.observe(element);
return () => {
if (element) observer.unobserve(element);
};
}, []);There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 83 out of 87 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (3)
front-end/src/schemas/rideSchema.ts:46
- The zod API for integer validation is incorrect. In zod v4,
z.int()is not a standalone method. Usez.number().int()instead.
Change z.int("Available seats must be an integer") to z.number().int({ message: "Available seats must be an integer" }).
front-end/src/schemas/rideSchema.ts:81
- The
z.enum()requires an array, not an enum object. This will cause a runtime error.
Change z.enum(RideStatus) to z.nativeEnum(RideStatus) to work with TypeScript enums.
front-end/src/app/(home)/ride/[...slug]/page.tsx:219
- The
isBookingAvailableprop is alwaystruein this call, but should be calculated based on the ride's remaining seats.
Change to: <BookingButton rideId={rideData._id} isBookingAvailable={rideData.remainingSeats > 0} />
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { z } from "zod"; | ||
|
|
||
| export const getUserRidesQuerySchema = z.object({ | ||
| type: z.enum(UserRideRole).prefault(UserRideRole.AS_PASSENGER).optional(), |
There was a problem hiding this comment.
In zod v4, the error message property should be message not error. The error property is not a valid zod option and will be ignored or cause errors.
Change { error: "..." } to { message: "..." } for all validation error messages.
| import { z } from "zod"; | ||
|
|
||
| export const getUserRidesQuerySchema = z.object({ | ||
| type: z.enum(UserRideRole).prefault(UserRideRole.AS_PASSENGER).optional(), |
There was a problem hiding this comment.
The z.enum() method requires an array of values, not an enum object. This will cause a runtime error.
Change z.enum(UserRideRole) to z.enum([UserRideRole.AS_PASSENGER, UserRideRole.AS_DRIVER]) or z.nativeEnum(UserRideRole) if you want to use the TypeScript enum directly.
| email: z.email({ | ||
| error: "emailError" | ||
| }).trim(), |
There was a problem hiding this comment.
The z.email() method must be chained after z.string(). Using z.email() directly is not valid in zod.
Change to: z.string().email({ message: "emailError" }).trim()
| email: z.email({ | |
| error: "emailError" | |
| }).trim(), | |
| email: z.string().email({ message: "emailError" }).trim(), |
| type: z.enum(UserRideRole).prefault(UserRideRole.AS_PASSENGER).optional(), | ||
| sortOrder: z.enum(["asc", "desc"]).prefault("asc").optional(), |
There was a problem hiding this comment.
The zod schema API has changed incorrectly. In zod v4, the correct method is default() not prefault(). The method name prefault appears to be a typo and will cause runtime errors.
All occurrences of .prefault() should be changed to .default().
| @@ -1,11 +1,11 @@ | |||
| import { Request, Response, NextFunction } from "express"; | |||
| import { z, ZodError } from "zod"; | |||
| import { z, ZodError, ZodSchema } from "zod"; | |||
There was a problem hiding this comment.
Unused import z.
| import { z, ZodError, ZodSchema } from "zod"; | |
| import { ZodError, ZodSchema } from "zod"; |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|




Implemented booking creation